package com.zhoukx.netty.codec;


import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;

/**
 * 简单的netty服务案例
 */
public class NettyServer {

    public static void main(String[] args) throws InterruptedException {


        // 创建BossGroup 和 workerGroup
        // 说明
        // 1.创建两个线程组bossGroup和workerGoup
        //2. bossgroup 只处理连接请求,真正和客户端业务处理,会交给workerGroup完成
        // 3.两个无线循环
        // bossGroup 和 workGroup 含有的子线程的个数
        // 默认实际cpu核数*2
        EventLoopGroup bossGroup = new NioEventLoopGroup();

        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            // 创建服务的启动对象,配置参数
            ServerBootstrap bootstrap = new ServerBootstrap();

            // 使用链式编程来进行设置   设置两个线程组
            bootstrap.group(bossGroup, workGroup)   // 设置两个线程组
                    .channel(NioServerSocketChannel.class)  // 视同NioSocketChannel 作为服务器的通道实现
                    .option(ChannelOption.SO_BACKLOG, 128) // 设置线程队列得到链接个数
                    .childOption(ChannelOption.SO_KEEPALIVE, true)  // 设置保持活动链接状态
                    .childHandler(new ChannelInitializer<SocketChannel>() {  // 创建一个管道测试对象(匿名对象)
                        // 给pipeline设置处理器
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            //pipeline 中加入 decoder
                            // 指定对那种对象进行解码
                            ch.pipeline().addLast("decoder",new ProtobufDecoder(StudentPOJO.Student.getDefaultInstance()));
                            ch.pipeline().addLast(new NettyServerHandler());
                        }
                    });  // 给我们的wokerGroup的 Eventloop对应的管道设置处理器

            //
            System.out.println("....服务器 is ready...");

            // 绑定一个端口,并且同步.生成一个channelFuture对象
            // 启动服务器(并且绑定端口)
            ChannelFuture sync = bootstrap.bind(6668).sync();

            // 给sync注册监听器,监控我们关心的事件
            sync.addListener(new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    if (sync.isSuccess()) {
                        System.out.println("监听端口   6668 成功");
                    } else {
                        System.out.println("监听端口 6668 失败");
                    }
                }
            });

            // 对关闭通道进行监听
            sync.channel().closeFuture().sync();

        } catch (Exception e) {
            bossGroup.shutdownGracefully();
            workGroup.shutdownGracefully();
        }
    }
}
